// **************************************************************
// Com ++ Framework by the C++ World
// Please report defects: mailto:compp@cplusplusworld.com
// Please visit: http://www.cplusplusworld.com/socketlibrary.html
// **************************************************************

#include <iostream>

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include "SysPlusPlus/syscall.h"

#include "ComPlusPlus/Process.h"
#include <sys/types.h>
#include <errno.h>
#include <sys/wait.h>


/**
 * Constructor. Sets SetAutoTerm to false
 **/
compp::Process::Process() {
 SetAutoTerm(false);
 Pid = syspp::Call::Getpid();
}

/**
 * Constructor. Sets Pid to p, name to an and AutoTerm to false
 **/
compp::Process::Process( std::string n) {

 SetAutoTerm(false);
 SetName(n);
 Pid = syspp::Call::Getpid();

}
/**
 * Destructor: If AutoTerm == true
 * kill process as well in operating system level
 * Termination of process in two attemts:
 * 1. graceful termination (SIGTERM)
 * 2. kill (SIGKILL)
 **/
compp::Process::~Process() {
 if ( TerminateInDestructor ) {
	GracefulTerminate();
	Terminate();
 }
}
/**
 * Modifier
 **/
void compp::Process::SetAutoTerm ( bool yn ) {
  TerminateInDestructor = yn;
}
/**
 * Modifier
 **/
void compp::Process::SetName( std::string s) {
 Name = s;
}

/**
 * Accessor
 **/
bool compp::Process::GetName( std::string &s) const {
 s = Name ;
 return true;
}


/**
 * Accessor
 **/
bool compp::Process::GetPid ( int &p ) const{
  
  p = Pid;
  return true;
}


/**
 * Accessor
 **/
int compp::Process::GetPid (  ) const{
  int p = Pid;
  return p;
}

/**
 * Suspends the process on Operating System level
 * by sending SIGSTOP 
 **/
bool compp::Process::Suspend(){
#ifdef SIGSTOP
  return SendSignal ( SIGSTOP );
#endif
}

/**
 * Continues the process on Operating System level
 * by sending SIGCONT
 **/
bool compp::Process::Continue(){
#ifdef SIGCONT
  return SendSignal ( SIGCONT );
#endif
}

/**
 * Terminates the process on Operating System level
 * by sending SIGKILL
 **/
bool compp::Process::Terminate(){
#ifdef SIGKILL
  return SendSignal ( SIGKILL );
#endif
}

/**
 * Terminates the process on Operating System level
 * by sending SIGKILL
 **/
bool compp::Process::TerminateGroup(){
#ifdef SIGKILL
  return  killpg(Pid, SIGKILL);

#endif
}


/**
 * Gracefully terminates the process on Operating System level
 * by sending SIGTERM
 **/
bool compp::Process::GracefulTerminate(){
#ifdef SIGTERM
  return SendSignal ( SIGTERM );
#endif
}

/**
 * Sends signal to Process
 **/
bool compp::Process::SendSignal ( int signo) {
int i;
 
  if ( signo < 0 ) {

  }

  i = syspp::Call::Kill ( Pid , signo ) ;
  
  if ( i != 0 ) {
    return false;
  }
  return true;
}

/**
 * Attention: This blocks either until 
 * (1) the process terminates or
 * (2) until hell freezes over
 **/
int compp::Process::Wait () {

  int status=0, i=0 ;
  i = Pid;
  int ret=0;
  ret = syspp::Call::Waitpid(i, &status, 0);
  
  std::cout << "Wait pid orig "<<Pid << "ret "  << ret << "i=" << i <<"\n";
  std::cout << "Errno " << errno <<"\n";
  perror ( "wait");
  

  if ( WIFEXITED ( status ) ) {
    std::cout << "WIFEXITED " << WEXITSTATUS ( status ) << "\n";
    return WEXITSTATUS ( status );
  }


  if ( WEXITSTATUS ( status ))  {
    std::cout << "WEXITSTATUS \n";

  }
  if ( WIFSIGNALED ( status ) ) {
    std::cout << "WIFSIGNALED \n";

  }
  if ( WTERMSIG ( status ) ) {
    std::cout << "WTERMSIG \n";

  }
  if ( WCOREDUMP ( status ) ) {
    std::cout << "WCOREDUMP \n";

  }
  if ( WIFSTOPPED ( status ) ) {
    std::cout << "WIFSTOPPED \n";

  }
  if ( WSTOPSIG ( status ) ) {
    std::cout << "WSTOPSIG \n";

  }
  if ( WIFCONTINUED ( status ) ) {
    std::cout << "WIFCONTINUED \n";
    return 1;
  }


  return status;

}

bool compp::Process::IsRunning () {

  int status, i ;
  i = Pid;
  if ( i != syspp::Call::Waitpid(i, &status, WNOHANG)) {
    return false;
  }

  return true;
}



